﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace xtst.CSharpDevUtility.ICollection
{
    public static class ICollectionExtsion
    {
        /// <summary>
        /// 检验集合是否为空
        /// </summary>
        public static bool IsEmptyOrNull<T>(this ICollection<T> toCheck)
        {
            return null == toCheck || toCheck.Count == 0;
        }

        /// <summary>
        /// 从TBase列表里获取所有T类型
        /// </summary>
        public static List<T> GetAll<T, TBase>(this ICollection<TBase> toGet)
            where T : TBase
        {
            return (from one in toGet where one is T select (T)one).ToList();
        }

        /// <summary>
        /// 检查TBase列表中是否存在T类型
        /// </summary>
        public static bool HaveType<T, TBase>(this ICollection<TBase> toGet)
            where T : TBase
        {
            return toGet.GetAll<T, TBase>().Count > 0;
        }

        /// <summary>
        /// 检查扩展，如果allwoDup为true，那么不允许重复
        /// </summary>
        public static ICollection<T> Append<T>(this ICollection<T> ori, ICollection<T> toAdd, bool allowDup = false)
        {
            if (allowDup)
            {
                return ori.Append(toAdd);
            }
            else
            {
                return ori.AppendNoDup(toAdd);
            }
        }

        /// <summary>
        /// 重复扩展
        /// </summary>
        private static ICollection<T> Append<T>(this ICollection<T> ori, ICollection<T> toAdd)
        {
            if (toAdd.IsEmptyOrNull())
            {
                return ori;
            }

            foreach (var one in toAdd)
            {
                ori.Add(one);
            }

            return ori;
        }

        /// <summary>
        /// 无重复扩展
        /// </summary>
        public static ICollection<T> AppendNoDup<T>(this ICollection<T> ori, ICollection<T> toAdd)
        {
            if (toAdd.IsEmptyOrNull())
            {
                return ori;
            }

            foreach (var one in toAdd)
            {
                if (!ori.Contains(one))
                {
                    ori.Add(one);
                }
            }

            return ori;
        }

        /// <summary>
        /// 无重复添加
        /// </summary>
        /// <returns>返回是否存在重复</returns>
        public static bool AddNoDup<T>(this ICollection<T> ori, T toAdd)
        {
            if (!ori.Contains(toAdd))
            {
                ori.Add(toAdd);
                return true;
            }

            return false;
        }

        /// <summary>
        /// 判断两个list是否存在交集
        /// </summary>
        public static bool IsListIntersectionExist<T>(this List<T> a, List<T> b)
        {
            List<T> temp = new List<T>(a.ToArray());
            temp.AppendNoDup(b);
            return temp.Count != (a.Count + b.Count);//不同就说明存在交集
        }

        /// <summary>
        /// 顺序是否一致
        /// </summary>
        public static bool IsListSeqSame<T>(this List<T> a, List<T> b)
        {
            if (a.IsListValueSame(b))
            {
                for (int i = 0; i < a.Count; i++)
                {
                    if (!a[i].Equals(b[i]))
                    {
                        return false;
                    }
                }

                return true;
            }

            return false;
        }

        /// <summary>
        /// 顺序是否一致
        /// </summary>
        public static bool IsListSeqSame<T>(this List<T> a, List<T> b, Delegates.Compare<T> compare)
        {
            if (a.IsListValueSame(b))
            {
                for (int i = 0; i < a.Count; i++)
                {
                    if (!compare(a[i], b[i]))
                    {
                        return false;
                    }
                }

                return true;
            }

            return false;
        }

        /// <summary>
        /// 是否值一致（不判定顺序）
        /// </summary>
        public static bool IsListValueSame<T>(this List<T> a, List<T> b)
        {
            if (a.Count != b.Count)
            {
                return false;
            }

            List<T> temp = new List<T>(b.ToArray());
            for (int i = 0; i < a.Count; i++)
            {
                temp.Remove(a[i]);
            }

            return temp.Count == 0;
        }

        /// <summary>
        /// 是否值一致（不判定顺序）
        /// </summary>
        public static bool IsListValueSame<T>(this List<T> a, List<T> b, Delegates.Compare<T> compare)
        {
            if (a.Count != b.Count)
            {
                return false;
            }

            List<T> temp = new List<T>(b.ToArray());
            for (int i = 0; i < a.Count; i++)
            {
                temp.Remove(a[i], compare);
            }

            return temp.Count == 0;
        }

        /// <summary>
        /// 检查删除（仅删除单一元素）
        /// </summary>
        public static bool Remove<T>(this List<T> a, T b, Delegates.Compare<T> compare)
        {
            for (int i = 0; i < a.Count; i++)
            {
                if (compare(a[i], b))
                {
                    a.RemoveAt(i);
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// 检查包含（任一）
        /// </summary>
        public static bool ContainsAny<T>(this ICollection<T> a, params T[] toCheck)
        {
            foreach (T thisS in a)
            {
                if (toCheck.Contains(thisS))
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// 检查包含（所有）
        /// </summary>
        public static bool ContainsAll<T>(this ICollection<T> a, params T[] toCheck)
        {
            if (a.Count < toCheck.Length)
            {
                return false;
            }

            foreach (var thisS in toCheck)
            {
                if (!a.Contains(thisS))
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// 检查包含（任一）
        /// </summary>
        public static bool ContainsAny<T>(this ICollection<T> a, Delegates.Check<T> checker)
        {
            foreach (var thisOne in a)
            {
                if (checker(thisOne))
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// 获取交集
        /// </summary>
        public static List<T> GetListIntersection<T>(this List<T> a, List<T> b)
        {
            List<T> res = new List<T>();
            for (int i = 0; i < b.Count; i++)
            {
                if (a.Contains(b[i]))
                {
                    res.Add(b[i]);
                }
            }
            return res;
        }

        /// <summary>
        /// 多元素去除
        /// </summary>
        public static List<T> RemoveList<T>(this List<T> a, List<T> toRemove)
        {
            for (int i = 0; i < toRemove.Count; i++)
            {
                a.Remove(toRemove[i]);
            }

            return a;
        }

        /// <summary>
        /// 检查删除（所有）
        /// </summary>
        public static List<T> RemoveBy<T>(this List<T> a, Delegates.Check<T> checker)
        {
            for (int i = 0; i < a.Count; i++)
            {
                if (checker(a[i]))
                {
                    a.RemoveAt(i);
                    i--;
                }
            }
            return a;
        }

        /// <summary>
        /// 安全启动 a = a.SaveInit
        /// </summary>
        public static List<T> SaveInit<T>(this List<T> toInit)
        {
            if (toInit != null)
            {
                toInit.Clear();
            }
            else
            {
                toInit = new List<T>();
            }

            return toInit;
        }

        /// <summary>
        /// 非空启动
        /// </summary>
        public static List<T> InitIfNull<T>(this List<T> toInit)
        {
            if (toInit.IsEmptyOrNull())
            {
                toInit.SaveInit();
            }

            return toInit;
        }

        /// <summary>
        /// 加入或者新建列
        /// </summary>
        public static void AddOrNew<TKey, T>(this Dictionary<TKey, List<T>> dictionary, TKey key, T value, bool allowDup = false)
        {
            if (dictionary.ContainsKey(key))
            {
                if (!allowDup && dictionary[key].Contains(value))
                {
                    return;
                }

                dictionary[key].Add(value);
            }
            else
            {
                dictionary.Add(key, new List<T>() { value });
            }
        }

        /// <summary>
        /// 加入或者扩展
        /// </summary>
        public static void AddOrAppend<TKey, T>(this Dictionary<TKey, List<T>> dictionary, TKey key, List<T> value, bool allowDup = false)
        {
            if (dictionary.ContainsKey(key))
            {
                for (int i = 0; i < value.Count; i++)
                {
                    dictionary.AddOrNew(key, value[i], allowDup);
                }
            }
            else
            {
                dictionary.Add(key, value);
            }
        }

        /// <summary>
        /// 检查加入
        /// </summary>
        public static void TrickyAdd<TKey, T>(this Dictionary<TKey, T> dictionary, TKey key, T value, bool cover = true)
        {
            if (key != null && (dictionary.ContainsKey(key) && cover))
            {
                dictionary[key] = value;
            }
            else if (key != null && !dictionary.ContainsKey(key))
            {
                dictionary.Add(key, value);
            }
        }

        /// <summary>
        /// 检查加入
        /// </summary>
        public static void TrickyAdd<TKey, T>(this Dictionary<TKey, T> dictionary, TKey key, T value, Delegates.Check<T> checker)
        {
            if (key != null && (dictionary.ContainsKey(key) && checker(value)))
            {
                dictionary[key] = value;
            }
            else if (key != null && !dictionary.ContainsKey(key))
            {
                dictionary.Add(key, value);
            }
        }

        /// <summary>
        /// 字典合并
        /// </summary>
        public static void MergeWith<TKey, TValue>(this Dictionary<TKey, List<TValue>> target, Dictionary<TKey, List<TValue>> toMerge)
        {
            foreach (var kvPair in toMerge)
            {
                target.AddOrAppend(kvPair.Key, kvPair.Value, false);
            }
        }

        public static void MergeWith<TKey, TValue>(this Dictionary<TKey, TValue> target, Dictionary<TKey, TValue> toMerge, bool useTargetIfDup)
        {
            foreach (var kvPair in toMerge)
            {
                target.TrickyAdd(kvPair.Key, kvPair.Value, useTargetIfDup);
            }
        }

        /// <summary>
        /// 安全获取
        /// </summary>
        public static T2 SaveGet<T1, T2>(this Dictionary<T1, T2> dictionary, T1 key)
        {
            if (key != null && dictionary.ContainsKey(key))
            {
                return dictionary[key];
            }
            else
            {
                return default(T2);
            }
        }

        /// <summary>
        /// 安全引用
        /// </summary>
        public static ICollection<T> SaveReference<T>(this ICollection<T> toGet)
        {
            if (toGet.IsEmptyOrNull())
            {
                return new List<T>();
            }

            return toGet;
        }

        /// <summary>
        /// 以某种判定方式切分
        /// </summary>
        public static Dictionary<bool, List<T>> DivideBy<T>(this ICollection<T> toDivide, Delegates.Check<T> checker)
        {
            Dictionary<bool, List<T>> res = new Dictionary<bool, List<T>>();

            res.Add(true, new List<T>());
            res.Add(false, new List<T>());

            foreach (var a in toDivide)
            {
                res.AddOrNew(checker(a), a);
            }

            return res;
        }

        /// <summary>
        /// 以某种计算值切分
        /// </summary>
        public static Dictionary<TKey, List<T>> DivideByValue<TKey, T>(this ICollection<T> toDivide, Delegates.Getter<TKey, T> getter)
        {
            Dictionary<TKey, List<T>> res = new Dictionary<TKey, List<T>>();

            foreach (var singleOne in toDivide)
            {
                res.AddOrNew(getter(singleOne), singleOne);
            }

            return res;
        }

        /// <summary>
        /// 找出所有符合条件的元素
        /// </summary>
        public static List<T> FindBy<T>(this ICollection<T> toFind, Delegates.Check<T> checker)
        {
            List<T> res = new List<T>();

            foreach (var a in toFind)
            {
                if (checker(a))
                {
                    res.Add(a);
                }
            }

            return res;
        }
        
        /// <summary>
        /// 非Equal包含
        /// </summary>
        public static bool Contains<T>(this List<T> a, Delegates.Check<T> checker)
        {
            for (int i = 0; i < a.Count; i++)
            {
                if (checker(a[i]))
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 去掉重复的
        /// </summary>
        public static List<T> RemoveAllDup<T>(this List<T> nodes)
        {
            for (int i = 0; i < nodes.Count; i++)
            {
                for (int j = 0; j < nodes.Count; j++)
                {
                    if (i == j)
                    {
                        continue;
                    }

                    if (nodes[i].Equals(nodes[j]))
                    {
                        nodes.RemoveAt(j);
                        if (j < i)
                        {
                            i--;
                        }

                        j--;
                    }
                }
            }

            return nodes;
        }

        /// <summary>
        /// 去掉重复的
        /// </summary>
        public static List<T> RemoveAllDup<T>(this List<T> nodes, Delegates.Compare<T> checker)
        {
            for (int i = 0; i < nodes.Count; i++)
            {
                for (int j = 0; j < nodes.Count; j++)
                {
                    if (i == j)
                    {
                        continue;
                    }

                    if (checker(nodes[i], nodes[j]))
                    {
                        nodes.RemoveAt(j);
                        if (j < i)
                        {
                            i--;
                        }

                        j--;
                    }
                }
            }

            return nodes;
        }
        

        /// <summary>
        /// 切分
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="toBreak"></param>
        /// <param name="breakP"></param>
        /// <returns></returns>
        public static List<List<T>> BreakInto<T>(this List<T> toBreak, T breakP) /*where T : class*/
        {
            if (!toBreak.Contains(breakP))
            {
                throw new Exception("[ICOEX][ListBreak] BreakPoint Not Contained!");
            }

            int index = toBreak.IndexOf(breakP);
            List<T> aft = new List<T>();
            for (int i = index; i < toBreak.Count; i++)
            {
                aft.Add(toBreak[i]);
            }

            List<T> bef = new List<T>();
            for (int i = 0; i < index + 1; i++)
            {
                bef.Add(toBreak[i]);
            }

            return new List<List<T>>() { bef, aft };
        }
       
        /// <summary>
        /// 旋转（指定元素）
        /// </summary>
        public static List<T> ReverseHeadToHead<T>(this List<T> toMove, T head)
        {
            return toMove.MoveLeftBy(toMove.IndexOf(head));
        }

        /// <summary>
        /// 旋转（指定方法）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="toMove"></param>
        /// <param name="checker"></param>
        /// <returns></returns>
        public static List<T> ReverseHeadToTarget<T>(this List<T> toMove, Delegates.Check<T> checker)
        {
            for (int i = 0; i < toMove.Count; i++)
            {
                if (checker(toMove[i]))
                {
                    return ReverseHeadToHead<T>(toMove, toMove[i]);
                }
            }

            return toMove;
        }

        /// <summary>
        /// 旋转（指定步长）
        /// </summary>
        public static List<T> MoveLeftBy<T>(this List<T> toMove, int step)
        {
            List<T> res = new List<T>();

            for (int i = 0; i < toMove.Count; i++)
            {
                res.Add(toMove[(i + step) % toMove.Count]);
            }

            return res;
        }

        /// <summary>
        /// 获取最小
        /// </summary>
        public static T GetMin<T>(this ICollection<T> toFind, Delegates.GetValue<T> getter)
        {
            T res = default(T);
            float min = Single.MaxValue;
            float thisV;
            foreach (var thisFind in toFind)
            {
                thisV = getter(thisFind);
                if (thisV < min)
                {
                    min = thisV;
                    res = thisFind;
                }
            }

            return res;
        }
        
        /// <summary>
        /// 获取最大
        /// </summary>
        public static T GetMax<T>(this ICollection<T> toFind, Delegates.GetValue<T> getter)
        {
            T res = default(T);
            float max = Single.MinValue;
            float thisV;
            foreach (var thisFind in toFind)
            {
                thisV = getter(thisFind);
                if (thisV > max)
                {
                    max = thisV;
                    res = thisFind;
                }
            }

            return res;
        }

        /// <summary>
        /// 最后一个
        /// </summary>
        public static T LastOne<T>(this List<T> list)
        {
            return list[list.Count - 1];
        }

        /// <summary>
        /// 最后n个（倒置下标）
        /// </summary>
        public static T LastOne<T>(this List<T> list, int fromLastIndex)
        {
            return list[list.Count - 1 - fromLastIndex];
        }

        /// <summary>
        /// 第一个
        /// </summary>
        public static T FirstOne<T>(this List<T> list)
        {
            return list[0];
        }

        /// <summary>
        /// 某个的下一个
        /// </summary>
        public static T NextOf<T>(this List<T> list, int index)
        {
            return list[(index + 1) % list.Count];
        }

        /// <summary>
        /// 某个的上一个
        /// </summary>
        public static T PreviousOf<T>(this List<T> list, int index)
        {
            int trueIndex = index - 1;
            if (trueIndex < 0)
            {
                return list.LastOne();
            }
            else
            {
                return list[trueIndex];
            }
        }

        /// <summary>
        /// 组集合并
        /// </summary>
        public static List<T> ChangeIntoSingleList<T>(this List<List<T>> toChange, bool allowDup = false)
        {
            List<T> res = new List<T>();

            for (int i = 0; i < toChange.Count; i++)
            {
                res.Append(toChange[i], allowDup);
            }

            return res;
        }

        /// <summary>
        /// 邻接表转化为连接层（层次遍历
        /// </summary>
        /// <returns></returns>
        public static List<List<T>> GetConnectLayer<T>(this Dictionary<T, List<T>> graph, T head)
        {
            List<List<T>> res = new List<List<T>>();

            List<T> visited = new List<T>() { head };
            List<T> lastLayer = new List<T>() { head };
            List<T> thisLayer = new List<T>();
            while (!lastLayer.IsEmptyOrNull())
            {
                for (int i = 0; i < lastLayer.Count; i++)
                {
                    thisLayer.AppendNoDup(graph[lastLayer[i]]);
                }
                thisLayer.RemoveList(visited);
                res.Add(thisLayer);
                lastLayer = thisLayer;
                thisLayer = new List<T>();
            }

            return res;
        }

        /// <summary>
        /// 计算层次
        /// </summary>
        public static int GetConnectLayerCount<T>(this List<List<T>> conLayer, T toGet)
        {
            for (int i = 0; i < conLayer.Count; i++)
            {
                if (conLayer[i].Contains(toGet))
                {
                    return i;
                }
            }

            return -1;
        }

        /// <summary>
        /// 连接组（联通分量）切分
        /// </summary>
        public static List<List<T>> GetConnectGroup<T>(this Dictionary<T, List<T>> conMap)
        {
            List<List<T>> res = new List<List<T>>();

            foreach (var kvPair in conMap)
            {
                List<T> toAdd = new List<T>();
                toAdd.AddNoDup(kvPair.Key);
                toAdd.AppendNoDup(kvPair.Value);
                res.Add(toAdd);
            }
            int counter = res.Count;
            for (int ii = 0; ii < counter; ii++)
            {
                for (int i = 0; i < res.Count; i++)
                {
                    for (int j = i + 1; j < res.Count; j++)
                    {
                        if (res[i].IsListIntersectionExist(res[j]))
                        {
                            res[i].AppendNoDup(res[j]);
                            res.RemoveAt(j);
                            j--;
                        }
                    }
                }
            }

            return res;
        }

        /// <summary>
        /// 字典倒置
        /// </summary>
        public static Dictionary<Tv, List<Tk>> ReverseKeyValue<Tk, Tv>(this Dictionary<Tk, List<Tv>> toReverse)
        {
            Dictionary<Tv, List<Tk>> res = new Dictionary<Tv, List<Tk>>();

            foreach (var kvPair in toReverse)
            {
                foreach (var v in kvPair.Value)
                {
                    res.AddOrNew(v, kvPair.Key);
                }
            }

            return res;
        }

        /// <summary>
        /// 生成邻接表
        /// </summary>
        public static Dictionary<T, List<T>> GetConnectMap<T>(this List<T> toGet, Delegates.Compare<T> isConnect)
        {
            Dictionary<T, List<T>> res = new Dictionary<T, List<T>>();

            for (int i = 0; i < toGet.Count; i++)
            {
                for (int j = i + 1; j < toGet.Count; j++)
                {
                    if (isConnect(toGet[i], toGet[j]))
                    {
                        res.AddOrNew(toGet[i], toGet[j]);
                    }

                    if (isConnect(toGet[j], toGet[i]))
                    {
                        res.AddOrNew(toGet[j], toGet[i]);
                    }
                }
            }

            return res;
        }

        /// <summary>
        /// 批量取值
        /// </summary>
        public static List<Tvalue> GetValueFrom<Ttype, Tvalue>(this List<Ttype> toGet, Delegates.GetValueFromType<Ttype, Tvalue> getValueFrom, bool allowDup = true, bool allowNull = false)
        {
            List<Tvalue> res = new List<Tvalue>();

            foreach (var thisOne in toGet)
            {
                var toAdd = getValueFrom(thisOne);
                if ((null == toAdd && allowNull) || null != toAdd)
                {
                    if (allowDup)
                    {
                        res.Add(toAdd);
                    }
                    else
                    {
                        res.AddNoDup(toAdd);
                    }
                }
            }

            return res;
        }

        public static List<T> DeepClone<T>(this List<T> toGet)
        {
            return new List<T>(toGet.ToArray());
        }

        /// <summary>
        /// 切分为组
        /// </summary>
        public static List<List<T>> DividedToGroup<T>(this List<T> toDivide, Delegates.Compare<T> isSameGroup)
        {
            List<T> _toDivide = toDivide.DeepClone();
            List<List<T>> res = new List<List<T>>();

            if (_toDivide.IsEmptyOrNull())
            {
                return res;
            }

            while (_toDivide.Count != 0)
            {
                List<T> thisGroup = new List<T>() { _toDivide[0] };// 初始化
                _toDivide.RemoveAt(0);
                thisGroup.AppendNoDup(_toDivide.FindBy(a => a.IsInSameGroup(thisGroup, isSameGroup)));
                _toDivide.RemoveList(thisGroup);
                res.Add(thisGroup);
            }

            return res;
        }

        /// <summary>
        /// 是否符合某条件组
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="toCheck"></param>
        /// <param name="group"></param>
        /// <param name="isSameGroup"></param>
        /// <returns></returns>
        public static bool IsInSameGroup<T>(this T toCheck, List<T> group, Delegates.Compare<T> isSameGroup)
        {
            if (group.IsEmptyOrNull())
            {
                return false;
            }

            foreach (var checker in group)
            {
                if (isSameGroup(checker, toCheck))
                {
                    return true;
                }
            }

            return false;
        }
    }
}